package com.mikufufu.blog.service.impl;

import com.mikufufu.blog.common.constant.Constant;
import com.mikufufu.blog.model.vo.admin.CategoryVO;
import com.mikufufu.blog.utils.BeanUtil;
import com.mikufufu.blog.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mikufufu.blog.mapper.CategoryMapper;
import com.mikufufu.blog.model.entity.Category;
import com.mikufufu.blog.service.CategoryService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.util.*;
import java.util.stream.Collectors;

/**
 *  服务实现类
 * 
 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {

    /**
     * 获取分类树结构。
     * 该方法首先尝试从缓存中获取分类树，如果缓存中存在，则直接返回缓存中的分类树。
     * 如果缓存中不存在，则从数据库中加载分类信息，构建分类树，并将构建好的分类树存储到缓存中。
     * 如果分类信息既不在缓存中也不在数据库中，则返回空列表。
     *
     * @return 返回分类树结构的列表。如果没有任何分类，则返回空列表。
     */
    @Override
    public List<CategoryVO> getCategoryTree(Integer type) {
        // 从数据库获取分类列表
        List<Category> categoryList = this.list(new LambdaQueryWrapper<Category>()
                .eq(StringUtils.isNotEmpty(type),Category::getCategoryType,type)
                .eq(Category::getStatus, 0));
        // 如果分类列表不为空，则构建分类树
        if (StringUtils.isNotEmpty(categoryList)) {
            return getTreeNavUseMap(categoryList);
        }
        // 若为空则直接返回空列表
        return Collections.emptyList();
    }

    /**
     * 基于分类列表和父级ID，构建分类树。
     * 首先将分类列表转换为Map，以类别ID为键，类别VO对象为值。
     * 然后调用buildCategoryTree方法，传入该Map和父级ID，构建树结构。
     *
     * @param categoryList 分类列表，不可为空。
     * @return 返回构建好的分类树结构列表。如果输入列表为空，则返回空列表。
     */
    private List<CategoryVO> getTreeNavUseMap(List<Category> categoryList) {
        if (StringUtils.isEmpty(categoryList)){
            return Collections.emptyList();
        }

        // 将分类列表转换为Map，便于快速查找
        Map<Integer, CategoryVO> categoryMap = new HashMap<>();
        categoryList.forEach(category -> {
            CategoryVO categoryVO = BeanUtil.copy(category, CategoryVO.class);
            categoryMap.put(category.getId(), categoryVO);
        });
        // 基于Map构建分类树
        return buildCategoryTree(categoryMap, Constant.TOP_PARENT_ID);
    }

    /**
     * 构建分类树。
     * 该方法通过给定的分类映射和父分类ID，构建一个分类树。每个分类可能有子分类，这个方法会递归地为每个父分类构建它的子分类树。
     *
     * @param categoryMap 分类映射，键为分类ID，值为CategoryVO对象，用于查找分类信息。
     * @param parentId 当前构建分类树的父分类ID。
     * @return 返回一个分类列表，代表从父分类开始的整个子分类树。
     */
    private List<CategoryVO> buildCategoryTree(Map<Integer, CategoryVO> categoryMap, Integer parentId) {
        // 从categoryMap中筛选出父ID为当前parentId的分类，然后为每个这类分类设置它的子分类树，最后按排序字段排序并收集到列表中
        return categoryMap.values().stream()
                // 筛选父ID匹配的分类
                .filter(categoryVO -> categoryVO.getParentId() != null &&  categoryVO.getParentId().equals(parentId))
                // 为每个分类设置它的子分类树
                .peek(categoryVO -> categoryVO.setChildren(buildCategoryTree(categoryMap, categoryVO.getId())))
                // 按排序字段排序
                .sorted(Comparator.comparingInt(Category::getSort))
                // 收集到列表中并返回
                .collect(Collectors.toList());
    }
}
